<?php defined('SYSPATH') or die('No direct script access.');

class Model_Audio extends ORM
{  
    protected $_reload_on_wakeup = false;
    
    protected $_background_filename = 'background';
    
    protected $_current_step = null;   
    public function set_current_step($step) {
        if (!array_key_exists($step, self::$steps)) {
            throw new Model_Exception('Такого шага нет');
        }
        $this->_current_step = $step;
    }
    
    protected $_current_edition = null;   
    public function set_current_edition($edition) {
        $this->_current_edition = $edition;
    }
    
    protected $_current_filename = null;   
    public function set_current_filename($filename) {
        $this->_current_filename = $filename;
    }
    
    protected $_current_background_filename = null;
    public function set_current_background_filename($filename) {
        $this->_current_background_filename = $filename;
    }

    public static $steps = array(
        'remove-noise'   => 'Удалите лишние фрагменты и уберите шумы',
        'first-compression' => 'Выполните компрессию',   
        'choose-music'   => 'Выберите фон ролика',   
        'merge-tracks'   => 'Наложите фон на ролик', 
        'second-compression' => 'Выполните компрессию',
        'download'       => 'Все готово! Скачайте файл',   
    );
    
    public static function load_audio($input_name)
    {        
        $audio = ORM::factory('audio');
        $audio->hash = time().mt_rand(1, 1000);
        $audio->save(); 
        
        $filename = Model_Main::upload_file($input_name, $audio->get_directory());
        
        // Преобразуем в стерео
        list($name, $ext) = explode('.', $filename);
        $new_filename = $name.'_stereo.'.$ext;
        
        Library_SoX::to_stereo($audio->get_directory().'/'.$filename, $audio->get_directory().'/'.$new_filename);
        
        $audio->filename = $new_filename;
        $audio->save();
        
        return $audio;
    }
    
    public function load_background($input_name)
    {        
        $filename = Model_Main::upload_file($input_name, $this->get_directory(), $this->_background_filename);
        return $this->get_clean_directory().'/'.$filename;
    }
    
    public static function get_by_hash($hash)
    {
        return ORM::factory('audio')
            ->where('hash', '=', $hash)
            ->find();
    }
    
    public function get_directory()
    {
        $dir = APPPATH.'../data/audio/';
        $dir = $dir.sprintf('%02x', $this->id % 0xff);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
        $dir = $dir.sprintf('/%d', $this->id);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
        return $dir;
    }
    
    public function get_clean_directory()
    {
        $dir = '/data/audio/';
        $dir = $dir.sprintf('%02x', $this->id % 0xff);
        $dir = $dir.sprintf('/%d', $this->id);
        return $dir;    
    }
    
    public function get_filename()
    {
        return $this->get_clean_directory().'/'.$this->filename;
    }
                    
    /**
    * Удаляет концы аудиозаписи. Другими словами, оставляет середину, отрезки которой переданы в параметрах
    *                                      
    * @param mixed $begin
    * @param mixed $end
    */
    public function trim_ends($begin, $end, $is_background = false) {
        $duration = $end - $begin;
        if ($duration <= 0) {
            throw new Model_Exception('Нулевая продолжительность');    
        }
        if ($is_background) {
            $old_filename = $this->_get_old_background_filename();
            $new_filename = $this->_get_new_background_filename();
            $clean_new_filename = $this->_get_new_background_filename(true);    
        } else {
            $old_filename = $this->_get_old_filename();
            $new_filename = $this->_get_new_filename();
            $clean_new_filename = $this->_get_new_filename(true);     
        }
        Library_SoX::trim($old_filename, $new_filename, $begin, $duration);
        return $clean_new_filename;
    }
    
    /**
    * Удаляет кусок из середины.
    *                                      
    * @param mixed $begin
    * @param mixed $end
    */
    public function trim_center($begin, $end) {
        $duration = $end - $begin;
        if ($duration <= 0) {
            throw new Model_Exception('Нулевая продолжительность');    
        }
        
        $part1 = $this->_get_custom_filename('p1');
        $part2 = $this->_get_custom_filename('p2');
        
        // Режем на 2 части
        Library_SoX::trim($this->_get_old_filename(), $part1, 0, $begin);
        Library_SoX::trim($this->_get_old_filename(), $part2, $end);
        
        // Клеим вместе
        Library_SoX::append($part1, $part2, $this->_get_new_filename());
        
        return $this->_get_new_filename(true);
    }
    
    /**
    * Изменить громкость у файла целиком
    * 
    * @param mixed $volume [0 - 1]
    */
    public function change_volume_of_whole($volume) {
        return true;    
    }
    
    /**
    * Изменить громкость у фрагмента
    * 
    * @param mixed $volume [0 - 1]
    */
    public function change_volume_of_fragment($volume, $begin, $end) {
        $duration = $end - $begin;
        if ($duration <= 0) {
            throw new Model_Exception('Нулевая продолжительность');    
        }
        
        $part1 = $this->_get_custom_filename('p1');
        $part2 = $this->_get_custom_filename('p2');
        $part3 = $this->_get_custom_filename('p3');
        
        // Режем на 3 части
        Library_SoX::trim($this->_get_old_filename(), $part1, 0, $begin);
        Library_SoX::trim($this->_get_old_filename(), $part2, $begin, $duration);
        Library_SoX::trim($this->_get_old_filename(), $part3, $end);
        
        // У средней убираем звук
        $part2vol = $this->_get_custom_filename('p2vol');
        Library_SoX::volume($part2, $part2vol, $volume);
        
        // Клеим вместе
        Library_SoX::append($part1, $part2vol, $part3, $this->_get_new_filename());
        
        return $this->_get_new_filename(true);   
    }
    
    /**
    * Компрессия
    * 
    */
    public function compand()
    {
        Library_SoX::compand($this->_get_old_filename(), $this->_get_new_filename(), '0.02,0.20 5:-60,-40,-10 -5 -90 0.1');
        
        return $this->_get_new_filename(true);
    }
    
    /**
    * Наложение фона на запись
    * 
    * @param mixed $track_volume        [0-1]
    * @param mixed $background_volume   [0-1]
    */
    public function merge($track_volume = 1, $background_volume = 1)
    {      
        Library_SoX::merge('-v '.self::_number_format(self::_interpolate_volume($track_volume)).' '.$this->_get_old_filename(),
                           '-v '.self::_number_format(self::_interpolate_volume($background_volume)).' '.$this->_get_old_background_filename(),
                           $this->_get_new_filename());
        
        return $this->_get_new_filename(true);
    }
    
    /**
    * Затухание концов записи.
    *                                      
    * @param mixed $begin
    * @param mixed $end
    */
    public function fade($begin, $end) {
        $duration = $end - $begin;
        if ($duration <= 0) {
            throw new Model_Exception('Нулевая продолжительность');    
        }
        
        Library_SoX::fade($this->_get_old_filename(), $this->_get_new_filename(), null, $end, $duration);
        
        return $this->_get_new_filename(true);
    }
    
    public function prepare_download()
    {
        list($name, $ext) = explode('.', $this->filename);
        $new_filename = $this->get_directory().'/'.$name.'(MixingVoice.com).'.$ext;
        copy($this->_get_old_filename(), $new_filename);
        return $new_filename;
    }                                   
    
    protected function _get_new_filename($clean = false)
    {
        $split = $this->_split_filename();
        $step  = str_replace('-', '', $this->_current_step);
        
        if ($clean) {
            $directory = $this->get_clean_directory();    
        } else {
            $directory = $this->get_directory();    
        }
        
        return $directory.'/'.$split['name'].'_'.$step.'_v'.$this->_current_edition.'.'.$split['ext'];    
    }
    
    protected function _get_old_filename()
    {
        return APPPATH.'..'.$this->_current_filename;
        /*$filename = $this->filename;
        if ($this->_current_edition > 1) {
            $split    = $this->_split_filename();
            $step     = str_replace('-', '', $this->_current_step);
            $edition  = $this->_current_edition - 1;
            $filename = $split['name'].'_'.$step.'_v'.$edition.'.'.$split['ext'];
        }
        return $this->get_directory().'/'.$filename;  */  
    }
    
    protected function _get_new_background_filename($clean = false)
    {
        list($name, $ext) = explode('.', $this->_current_background_filename);
        $name = $this->_background_filename;
        $step  = str_replace('-', '', $this->_current_step);
        
        if ($clean) {
            $directory = $this->get_clean_directory();    
        } else {
            $directory = $this->get_directory();    
        }
        
        return $directory.'/'.$name.'_'.$step.'_v'.$this->_current_edition.'.'.$ext;    
    }
    
    protected function _get_old_background_filename()
    {
        return APPPATH.'..'.$this->_current_background_filename;    
    }
    
    protected function _get_custom_filename($name)
    {
        $split    = $this->_split_filename();
        $step     = str_replace('-', '', $this->_current_step);
        $edition  = $this->_current_edition;
        $filename = $split['name'].'_'.$step.'_v'.$edition.$name.'.'.$split['ext'];

        return $this->get_directory().'/'.$filename;    
    }
    
    protected function _split_filename()
    {
        list($name, $ext) = explode('.', $this->filename);
        return array(
            'name' => $name,
            'ext'  => $ext,
        );
    }
    
    /**
    * Получает число [0, 1], 0.5 - середина, возвращает [0, 10], 1 - середина
    * 
    * @param mixed $old_volume
    */
    protected static function _interpolate_volume($old_volume)
    {
        $new_volume = null;
        if ($old_volume < 0.5) {
            $new_volume = $old_volume;    
        } else {
            $new_volume = $old_volume*2;     
        } 
        return $new_volume;
    }
    
    protected static function _number_format($number)
    {
        if ($number == 1) {
            return 1;
        }
        return number_format($number, 2, '.', '');
    }
}